package com.sxd.bill.rela.extractor;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import com.sxd.bill.common.enums.LabelNameEnum;
import com.sxd.bill.common.item.LabelItem;
import com.sxd.bill.common.item.TextLabelItem;
import com.sxd.bill.rela.item.CoreRelationItem;
import com.sxd.bill.rela.item.Template;
import com.sxd.bill.rela.item.TemplateResult;

/**
 * 多要素主体抽取器
 * 用于单条文本中含有多个要素主体的情况，
 * 如：
 * "收12月国贴大商及1.2月国贴城农、财司电商高价票，欢迎清单报价"
 * "出少量9月到期双国股，2月到期双国股"
 **/
public class MultiSubjectExtractor extends TemplateExtractor {
    @Override
    public String toString() {
        return "MultiSubjectExtractor(templates=[...])";
    }

    @Override
    protected List<Map<String, String>> extractFromTemplates(String text) {
        // 遍历每个Template抽取
        List<TemplateResult> results = new ArrayList<>();
        for (Template template : templates) {
            TemplateResult rst = template.extract(text);
            if (rst.size() > 0) {
                results.add(rst);
            }
        }
        List<Map<String, String>> output = new ArrayList<>();

        if (results.size() > 0) {
            // 按首个实体索引位置前后，总实体数量数量多少，排序取第一个
            TemplateResult bestResult = Collections.max(results,
                    Comparator.comparingInt(TemplateResult::getFirstEntityStartIndex).reversed()
                            .thenComparingInt(TemplateResult::size));

            int takeplaceCount = bestResult.getMatchedTextEndIndex() - bestResult.getMatchedTextStartIndex();
            String newText = text.substring(0, bestResult.getMatchedTextStartIndex()) +
                    new String(new char[takeplaceCount]).replace("\0", "$")
                    + text.substring(bestResult.getMatchedTextEndIndex());
            output.addAll(bestResult.getRelationMaps());
            output.addAll(extractFromTemplates(newText));
        }
        return output;
    }

    private static void fixUpDiscounters(List<CoreRelationItem> relaItems, List<LabelItem> labelItems) {
        // 标签按位置逆序排序
        labelItems.sort(Comparator.comparing(LabelItem::getStartIndex).reversed());
        // 从后往前找贴现人标签，若遇到非贴现人标签，则停止
        List<String> discounters = new ArrayList<>();
        for (LabelItem labelItem : labelItems) {
            if (labelItem.getLabelName().equals(LabelNameEnum.DISCOUNTER)) {
                discounters.add(labelItem.getLabelEntity());
            } else {
                break;
            }
        }
        if (discounters.size() > 0 && relaItems.size() > 0) {
            List<String> tmp_last_discounter = relaItems.get(relaItems.size() - 1).getDiscounter();
            List<String> lastDiscounter = tmp_last_discounter.size() > 0 ? tmp_last_discounter : discounters;
            for (int i = relaItems.size() - 1; i >= 0; i--) {
                CoreRelationItem item = relaItems.get(i);
                if (i == (relaItems.size() - 1) || item.getDiscounter().size() == 0) {
                    item.setDiscounter(lastDiscounter);
                } else {
                    break;
                }
            }
        }
    }

    private static void fixUpDueTime(List<CoreRelationItem> relaItems, List<LabelItem> labelItems) {
        // 标签按位置顺序排序
        labelItems.sort(Comparator.comparing(LabelItem::getStartIndex));

        List<String> preDueTime = new ArrayList<>();
        for (LabelItem labelItem : labelItems) {
            if (labelItem.getLabelName().equals(LabelNameEnum.DUE_TIME)) {
                preDueTime.add(labelItem.getLabelEntity());
            } else {
                break;
            }
        }
        for (CoreRelationItem item : relaItems) {
            List<String> curDueTime = item.getDueTime();
            if (curDueTime.size() == 0) {
                item.setDueTime(preDueTime);
            } else {
                preDueTime = curDueTime;
            }
        }
    }

    @Override
    public List<CoreRelationItem> extract(TextLabelItem textLabelItem) {
        List<CoreRelationItem> relaItems = super.extract(textLabelItem);
        List<LabelItem> labelItems = textLabelItem.getLabelItems();

        // // 标签按位置从低到高排序
        // labelItems.sort((a, b) -> a.getStartIndex() - b.getStartIndex());
        // // case 1: 没有提取出`贴现人`情况
        // long relaDiscountersCnt = relaItems.stream()
        // .flatMap(item -> item.getDiscounter().stream())
        // .collect(Collectors.counting());
        // List<String> discounters = labelItems.stream()
        // .filter(item -> item.getLabelName().equals(LabelNameEnum.DISCOUNTER))
        // .map(item -> item.getLabelEntity())
        // .collect(Collectors.toList());
        // // 更新`贴现人`
        // if (relaDiscountersCnt == 0 && discounters.size() > 0) {
        // relaItems.forEach(item -> item.setDiscounter(discounters));
        // }

        // case 1: 没有提取出`贴现人`情况(有遗漏或者未捕捉到)
        fixUpDiscounters(relaItems, labelItems);
        // case 2: 如果票据期限提取完整（本应有`票据期限`，但所有relatonItem都没提取到，或者部分relationItem没有提取到)
        fixUpDueTime(relaItems, labelItems);

        return relaItems;
    }

}
